package com.blockchain.nodes.manager.service.impl;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.blockchain.nodes.bitcoin.jsonrpcclient.BitcoinException;
import com.blockchain.nodes.common.enums.BillType;
import com.blockchain.nodes.common.enums.TransStatus;
import com.blockchain.nodes.manager.config.NodesConfiguration;
import com.blockchain.nodes.manager.domain.AccountAddress;
import com.blockchain.nodes.manager.domain.BtcNodeInfo;
import com.blockchain.nodes.manager.domain.NodesConfig;
import com.blockchain.nodes.manager.mapper.AccountAddressMapper;
import com.blockchain.nodes.manager.mapper.NodesConfigMapper;
import com.blockchain.nodes.manager.mapper.TransactionFlowMapper;
import com.blockchain.nodes.manager.service.Bitcoin;
import com.blockchain.nodes.manager.service.Bitcoin.RawTransaction;
import com.blockchain.nodes.manager.service.Bitcoin.Unspent;
import com.blockchain.nodes.manager.service.NodeTaskService;
import com.blockchain.nodes.manager.vo.TransactionAccountVO;
import com.blockchain.nodes.manager.vo.UserBanlanceVO;
import com.neemre.btcdcli4j.core.domain.Output;
import com.neemre.btcdcli4j.core.domain.Transaction;

@Component
public class NodeTaskServiceImpl implements NodeTaskService{
	private static final Logger L = LoggerFactory.getLogger(NodeTaskServiceImpl.class);

	@Autowired
	private TransactionFlowMapper transactionFlowMapper;
	
	@Autowired
	private AccountAddressMapper accountAddressMapper;
	
	@Autowired
	private  NodesConfigMapper nodesConfigMapper;
	@Autowired
	private Bitcoin bitcoin;


	/**
	 * 更新交易流水状态
	 * 每5分钟触发一次
	 * @Scheduled(cron = "0 0/5 * * * ?")
	 */
	public void updateTransActionStatus() {
		try {
			List<TransactionAccountVO> list = transactionFlowMapper.selectTransactionFlow();
			// 拉取所有钱包余额
			Map<String, AccountAddress> addressesMap = new HashMap<String, AccountAddress>();
			L.info("交易记录长度{}", list.size());
			if (!list.isEmpty() && list.size() > 0) {
				//有相同hash值
				Map<String, Integer> map = new HashMap<String, Integer>();
				for (TransactionAccountVO transactionAccountVO : list) {
					if (getDays(transactionAccountVO.getTransTime()) < 1) {
						if (StringUtils.isNotBlank(transactionAccountVO.getTransHash()) && StringUtils.isNotEmpty(transactionAccountVO.getTransHash())) {
							if (map.get(transactionAccountVO.getTransHash()) == null) {
								BtcNodeInfo nodeInfo = getNodeById(transactionAccountVO.getNodeId());
								if(nodeInfo!=null) {
									L.info("节点信息{},交易Hash{}",JSON.toJSONString(nodeInfo),transactionAccountVO.getTransHash());
									RawTransaction transaction =null;
									try {
										transaction = bitcoin.getTransaction(nodeInfo, transactionAccountVO.getTransHash());
										if(transaction==null) {
											continue;
										}
									} catch (BitcoinException e) {
										continue;
									}
									map.put(transactionAccountVO.getTransHash(), transaction.confirmations());
									if(transaction!=null  && transaction.confirmations()>5) {
										L.info("初始确认信息{}",JSON.toJSONString(transactionAccountVO));
										transactionFlowMapper.updateTransactionStatus(TransStatus.SUCCESS.getCode(), transactionAccountVO.getTransFlowId());
										//链资产接收 若链资产转出为系统地址，在转出时已减余额，无须重新拉取地址余额
										if(BillType.NODEIN.getCode().equals(transactionAccountVO.getBillType())) {
											AccountAddress accountAddress = accountAddressMapper.selectAccountAddressByAddress(transactionAccountVO.getTurnInWallet());
											L.info("初始链资产接收{}",JSON.toJSONString(accountAddress));
											addressesMap.put(accountAddress.getWalletAddress(), accountAddress);
										}
									}
								}
							} else {
								if (map.get(transactionAccountVO.getTransHash()) != null && map.get(transactionAccountVO.getTransHash()) > 5) {
									L.info("否则确认信息{}",JSON.toJSONString(transactionAccountVO));
									transactionFlowMapper.updateTransactionStatus(TransStatus.SUCCESS.getCode(), transactionAccountVO.getTransFlowId());
									//链资产接收 若链资产转出为系统地址，在转出时已减余额，无须重新拉取地址余额
									if(BillType.NODEIN.getCode().equals(transactionAccountVO.getBillType())) {
										AccountAddress accountAddress = accountAddressMapper.selectAccountAddressByAddress(transactionAccountVO.getTurnInWallet());
										L.info("否则链资产接收{}",JSON.toJSONString(accountAddress));
										addressesMap.put(accountAddress.getWalletAddress(), accountAddress);
									}
								}
							}

						}
					} else {
						L.info("交易失败信息：" + JSON.toJSONString(transactionAccountVO));
						transactionFlowMapper.updateTransactionStatus(TransStatus.FAIL.getCode(), transactionAccountVO.getTransFlowId());
					}
				}

			}
			
			// 拉取余额
			List<UserBanlanceVO> result = new ArrayList<UserBanlanceVO>();
			for (String key : addressesMap.keySet()) {
				L.info("需要拉取余额地址信息{}",JSON.toJSONString(addressesMap.get(key)));
				BtcNodeInfo nodeInfo = getNodeById(addressesMap.get(key).getNodeId());
				if(nodeInfo!=null) {
					try {
						BigDecimal balance  = new BigDecimal("0");
						List<Unspent>	unspents  = bitcoin.listUnspent(nodeInfo, 0, 999999999, addressesMap.get(key).getWalletAddress());
						if(unspents!=null&& unspents.size()>0) {
							for (Unspent unspent : unspents) {
								balance = balance.add(new BigDecimal(unspent.amount()));
							}
						}
						
						UserBanlanceVO userBanlanceVO = new UserBanlanceVO();
						userBanlanceVO.setWalletAlias(addressesMap.get(key).getWalletAlias());
						if (balance.setScale(4, BigDecimal.ROUND_DOWN).doubleValue() > 0) {
							Long amount = (long) ((balance.setScale(8, BigDecimal.ROUND_DOWN).doubleValue()) * 100000000);
							userBanlanceVO.setAmount(amount);
						} else {
							userBanlanceVO.setAmount(0L);
						}
						result.add(userBanlanceVO);
					
					} catch (BitcoinException e) {
						continue;
					}
					
				}
			}
			L.info("更新交易余额信息数量{}", result.size());
			if (result.size() > 0) {
				accountAddressMapper.updateBatchUserWalletBalance(result);
			}
		} catch (Exception e) {
			L.error("更新交易流水异常",e);
		}
	}

	/**
	 * 如果大于一天，设置为失败
	 * 
	 * @return
	 */
	private Long getDays(Date beginDate) {
		Date currDate = new Date();
		return (currDate.getTime() - beginDate.getTime()) / (60 * 60 * 1000 * 24);// 几天

	}

	/**
	 * 根据ID获取节点信息
	 * 
	 * @param nodeId
	 * @return
	 */
	private BtcNodeInfo getNodeById(Integer nodeId) {
		NodesConfig nodesConfig = nodesConfigMapper.selectNodesConfigById(nodeId);
		BtcNodeInfo btcNodeInfo = JSON.parseObject(nodesConfig.getNodeValue(), BtcNodeInfo.class);
		return btcNodeInfo;
	}
	

}
